home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The PC-SIG Library 9
/
The PC-SIG Library on CD ROM - Ninth Edition.iso
/
001_100
/
DISK0041
/
DISK0041.ZIP
/
MSKERM.ASM
< prev
next >
Wrap
Assembly Source File
|
1984-12-08
|
36KB
|
1,425 lines
public prompt, dosnum, curdsk, fpush
include msdefs.h
;******************** Version 2.27 **********************************
; KERMIT, Celtic for "free"
;
; The name "Kermit" is a registered trade mark of Henson Associates, Inc.,
; used by permission.
;
; Kermit-MS Program Version 2.27, December 6,1984
;
; Based on the Columbia University KERMIT Protocol.
;
; Copyright (C) 1982,1983,1984 Trustees of Columbia University
;
; Daphne Tzoar, Jeff Damens
; Columbia University Center for Computing Activities
; 612 West 115th Street
; New York, NY 10025
;
; Special thanks to Frank da Cruz, Bill Catchings, Steve Jensen, Herm Fischer,
; Vace Kundakci, and Bernie Eiben for their help and contributions.
makseg equ 26H
deffcb equ 5cH
setblk equ 4AH
exec equ 4BH
env equ 2CH ; environment address in psp
terma equ 10 ; termination address in psp
cline equ 80H ; offset in psp of command line
namsiz equ 20 ; Bytes for file name and size.
maxnam equ 10
chmod equ 43H ; chmod call (used to test for file existence)
STACK SEGMENT PARA STACK 'STACK'
DW 100 DUP(0) ; Initialize stack to all zeros.
STK EQU THIS WORD
STACK ENDS
datas segment public 'datas'
extrn buff:byte, comand:byte, flags:byte, pack:byte, trans:byte
extrn fcb:byte, cpfcb:byte, prmptr:word, inichk:byte
extrn machnam:byte
public takadr,taklev
versio label byte
verdef
db cr,lf
db 'Type ? for help',cr,lf
db '$'
tmp db ?,'$'
crlf db cr,lf,'$'
ermes1 db cr,lf,'?Unrecognized command$'
ermes3 db cr,lf,'?Not confirmed$'
erms30 db cr,lf,'Passed maximum nesting level for TAKE command$'
erms31 db cr,lf,'Take file not found$'
erms32 db cr,lf,'File(s) not found$'
erms33 db cr,lf,'CHKDSK program not found on current disk$'
erms34 db cr,lf,'This command works only for DOS 2.0 and above$'
erms35 db cr,lf,'Must specify program name$'
erms36 db cr,lf,'Could not free memory$'
erms37 db cr,lf,'Unable to execute program$'
infms1 db 'Really erase *.*? $'
infms8 db cr,lf,'File(s) erased$'
tmsg5 db cr,lf,'[closing log file]',cr,lf,'$' ; [jd]
filhlp1 db ' Command file specification $'
filhlp2 db ' File specification (possibly wild) $'
filhlp3 db ' File spec (possibly wild) or confirm with carriage return$'
filmsg db ' File specification with optional path name $'
filwmsg db ' File specification (possibly wild) with optional path name $'
chkfil db 0,'CHKDSK COM'
chkflen equ $-chkfil
tophlp db cr,lf
db 'BYE',tab,tab
db 'CLOSE',tab,tab
db 'CONNECT',tab,tab
db 'DEFINE',tab,tab
db cr,lf
db 'DELETE',tab,tab
db 'DIRECTORY',tab
db 'DO',tab,tab
db 'EXIT',tab,tab
db cr,lf
db 'FINISH',tab,tab
db 'GET',tab,tab
db 'HELP',tab,tab
db 'LOCAL',tab,tab
db cr,lf
db 'LOG',tab,tab
db 'LOGOUT',tab,tab
db 'PUSH',tab,tab
db 'QUIT',tab,tab
db cr,lf
db 'RECEIVE',tab,tab
db 'REMOTE',tab,tab
db 'RUN',tab,tab
db 'SEND',tab,tab
db cr,lf
db 'SERVER',tab,tab
db 'SET',tab,tab
db 'SHOW',tab,tab
db 'SPACE',tab,tab
db cr,lf
db 'STATUS',tab,tab
db 'TAKE'
db '$'
lochlp db cr,lf,'DELETE file'
db cr,lf,'DIRECTORY [filespec]'
db cr,lf,'SPACE remaining on current disk'
db cr,lf,'RUN program'
db cr,lf,'PUSH to command interpreter'
db '$'
; COMND tables
yestab db 2
mkeyw 'NO',0
mkeyw 'YES',1
comtab db 27
mkeyw 'BYE',bye
mkeyw 'C',telnet
mkeyw 'CLOSE',clscpt
mkeyw 'CONNECT',telnet
mkeyw 'DEFINE',dodef
mkeyw 'DELETE',delete
mkeyw 'DIRECTORY',direct
mkeyw 'DO',docom
mkeyw 'EXIT',exit
mkeyw 'FINISH',finish
mkeyw 'GET',get
mkeyw 'HELP',help
mkeyw 'LOCAL',lclcmd
mkeyw 'LOG',setcpt
mkeyw 'LOGOUT',logout
mkeyw 'PUSH',dopush
mkeyw 'QUIT',exit
mkeyw 'RECEIVE',read
mkeyw 'REMOTE',remote
mkeyw 'RUN',run
mkeyw 'SEND',send
mkeyw 'SERVER',server
mkeyw 'SET',setcom
mkeyw 'SHOW',showcmd
mkeyw 'SPACE',chkdsk
mkeyw 'STATUS',status
mkeyw 'TAKE',take
loctab db 5
mkeyw 'DELETE',delete
mkeyw 'DIRECTORY',direct
mkeyw 'PUSH',dopush
mkeyw 'RUN',run
mkeyw 'SPACE',chkdsk
shotab db 2
mkeyw 'KEY',shokey
mkeyw 'MACROS',shomac
; Program storage.
oldstk dw ? ; Storage for system stack.
oldsts dw ? ; System stack segment.
ssave dw ? ; Original SS when doing CHKDSK.
siz dw ? ; Memory size.
in3ad dd 0 ; Original break interrupt addresses. [25]
curdsk db 0 ; Current disk.
origd db 0 ; Original disk.
fildat db 0 ; Manipulate file data/time creation.
db 0
taklev db 0 ; Take levels. [25t]
takadr dw takstr-(size takinfo) ; Pointer into structure. [25t]
temp dw 0
temp1 dw ? ; Temporary storage.
temp2 dw ?
temp3 dw ?
temp4 dw ?
psp dw ?
divst dw 0
takstr db (size takinfo) * maxtak dup(?)
ininam db 0,'MSKERMITINI' ; init file name, on default disk, 12 chars
ininm2 db 'MSKERMIT.INI',0 ; init file name for 2.0
nambuf db maxnam * namsiz dup (?)
cmdnam db namsiz dup (?)
exefcb db fcbsiz dup (?)
exefcb2 db fcbsiz dup (?)
exearg dw ? ; segment addr of environment (filled in below)
dd 0 ; ptr to cmd line (filled in below)
dd exefcb ; default fcb
dd exefcb2 ; second default fcb
dircmd db ' /c dir '
dirclen equ $-dircmd
dirnam db 50h dup (?)
chkdcmd db 'chkdsk.com'
chkdlen equ $-chkdcmd
dosnum db ? ; dos version number
pthnam db 'PATH='
pthlen equ $-pthnam
pthbuf db 100 dup (?) ; buffer for path definition.
defpth db '\', 70 dup (?) ; buffer for default path
cmspnam db 'COMSPEC='
cmsplen equ $-cmspnam
cmspbuf db '\command.com',0 ; default name
db 30 dup (?) ; some additional space
tfile db 100 dup (?) ; temp space for file names.
eexit db cr,'exit',cr
leexit equ $-eexit
datas ends ; End data segment
code segment public
public takrd
start proc far
extrn cmblnk:near, locate:near, logout:near
extrn bye:near, telnet:near, finish:near, comnd:near
extrn read:near, remote:near, send:near, status:near, get:near
extrn dodisk:near, serrst:near, setcom:near
extrn clscpi:near, clscpt:near, getbaud:near
extrn dodef:near, setcpt:near, docom:near
extrn server:near, lclini:near, shokey:near, shomac:near
extrn packlen:near
assume cs:code,ds:datas,ss:stack,es:nothing
push ds ; Save system data area.
sub ax,ax ; Get a zero.
push ax ; Put zero return addr on stack.
mov ax,datas ; Initialize DS.
mov ds,ax
sub ax,ax
mov oldstk,sp ; Save old stack pointer.
mov ax,es:[2] ; In program segment prefix
mov siz,ax ; Pick up memory size
mov psp,es
mov ah,prstr
mov dx,offset machnam ; print machine name
int dos
mov ah,prstr ; Print the version header.
mov dx,offset versio
int dos
mov ah,setdma ; Set disk transfer address.
mov dx,offset buff
int dos
call getbaud ; Get the baud rate. [25]
call dodisk ; See how many disk drives we have. [21a]
call setint
mov ah,gcurdsk ; Get current disk.
int dos
inc al ; We want 1 == A (not zero).
mov curdsk,al
mov origd,al ; Remember original disk we started on.
mov ah,dosver
int dos
mov dosnum,al ; remember dos version
cmp al,0
je start1 ; 1.1, keep going
mov es,psp
mov ax,es:[env] ; pick up environment address
push ax
call getpath ; get the path from the environment
pop ax ; get environment back
call getcsp ; get comspec from environment as well
start1: call lclini ; do local initialization
call gcmdlin ; read command line
call rdinit ; read kermit init file
call packlen ; Packet length in case do server comand.
; This is the main KERMIT loop. It prompts for and gets the users commands.
kermit: mov ax,ds
mov es,ax ; make sure this addresses data segment
mov dx,prmptr ; get prompt
call prompt ; Prompt the user.
mov pack.state,0 ; Clear the state.
mov flags.cxzflg,0 ; Reset each itme.
mov ah,inichk ; Original or set checksum length.
mov trans.chklen,ah ; Reset just in case.
mov dx,offset comtab
mov bx,offset tophlp
mov comand.cmcr,1 ; Allow bare CR's.
mov ah,cmkey
call comnd
jmp kermt2
mov comand.cmcr,0 ; Not anymore.
call bx ; Call the routine returned.
jmp kermt3
cmp flags.extflg,0 ; Check if the exit flag is set.
jne krmend ; If so jump to KRMEND.
jmp kermit ; Do it again.
kermt2: mov dx,offset ermes1 ; Give an error.
jmp short kermt4
kermt3: mov dx,offset ermes3 ; Give an error.
kermt4: cmp flags.cxzflg,'C' ; some sort of abort?
je kermit ; yes, don't print error message.
mov ah,prstr
int dos
mov flags.droflg,0 ; Reset drive override flag.
mov flags.nmoflg,0 ; Reset filename override flag.
mov flags.getflg,0 ; May as well do this one.
mov flags.cmrflg,0 ; This one too.
jmp kermit
krmend: call serrst ; Just in case the port wasn't reset. [21c]
mov dl,origd ; Original disk drive.
dec dl ; Want A == 0.
mov ah,seldsk ; Reset original disk just in case.
int dos
mov sp,oldstk
ret
START ENDP
; This is the 'exit' command. It leaves KERMIT and returns to DOS.
EXIT PROC NEAR
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r
test flags.capflg,0FFH ; capturing?
jz exit1 ; no, keep going
mov dx,offset tmsg5
mov ah,prstr
int dos
call clscpi
nop ; this skip returns...
nop
nop
exit1:
mov flags.extflg,1 ; Set the exit flag.
jmp rskp ; Then return to system.
EXIT ENDP
; This is the 'help' command. It gives a list of the commands.
HELP PROC NEAR
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r
mov ah,prstr ; Print a string to the console.
mov dx,offset tophlp ; The address of the help message.
int dos
jmp rskp
HELP ENDP
lclcmd proc near
mov ah,cmkey
mov dx,offset loctab
mov bx,offset lochlp
call comnd
jmp r
call bx
nop
nop
nop
jmp rskp
lclcmd endp
; Don't ignore ^C when in debug mode.
SETINT PROC NEAR
push ds ; Don't forget this. [25]
mov ax,ds
mov es,ax ; So can access our data area.
mov ax,0
mov ds,ax ; Access low core.
mov ax,ds:[23H * 4] ; Address for interrupt 23H.
mov cx,ds:[23H * 4 +2] ; CS value for it.
mov word ptr es:in3ad,ax ; Remember original values.
mov word ptr es:in3ad+2,cx
mov ax,cs
mov ds,ax ; Access code are.
mov dx,offset intbrk
mov al,23H ; On ^C, goto above address.
mov ah,25H
int dos
pop ds
ret
SETINT ENDP
; take commands from a file, but allow a path name
PTAKE PROC NEAR
cmp taklev,maxtak ; Hit our limit?
jl ptake1 ; Continue if still OK.
mov ah,prstr
mov dx,offset erms30 ; Complain.
int dos
ret
ptake1: mov di,takadr
add di,size takinfo
push di
mov ah,cmtxt
lea bx,[di].takbuf ; convenient place to parse name into
mov dx,offset filmsg ; Help in case user types "?".
call comnd
pop di
ret
nop
pop di ; restore frame address
cmp ah,0
je ptake2 ; empty, complain.
push di ; keep it on stack.
lea si,[di].takbuf ; get buffer back
mov bl,ah ; length of thing parsed
mov bh,0
mov byte ptr [bx+si],0 ; make it asciz
mov ax,si ; point to name again
call spath ; is it around?
pop di ; need this back
jc ptake2 ; no, go complain
mov dx,ax ; point to name from spath
mov ah,open2 ; 2.0 open call
mov al,0 ; open for reading
int dos
jnc ptake3 ; open ok, keep going
ptake2: mov ah,prstr
mov dx,offset erms31
int dos
ret
ptake3: inc taklev
mov takadr,di
mov word ptr [di].takfcb+1,ax ; save file descriptor
mov byte ptr [di].takfcb,0feh ; mark as 2.0 file descriptor
mov bx,ax ; need descriptor here
mov ah,lseek
mov al,2
mov cx,0
mov dx,cx ; seek 0 bytes from end
int dos
mov [di].takcnt,ax
mov [di].takcnt+2,dx ; store length
mov ah,lseek
mov al,0
mov cx,0
mov dx,cx ; now seek back to beginning
int dos
cmp flags.takflg,0
je ptake4
mov ah,prstr
mov dx,offset crlf
int dos
ptake4: call takrd ; Get a buffer full of data.
jmp rskp
PTAKE ENDP
; TAKE commands from a file. [25t]
TAKE PROC NEAR
cmp dosnum,0
je take1
jmp ptake ; use this for 2.0
take1: cmp taklev,maxtak ; Hit our limit?
jl take2 ; Continue if still OK.
mov ah,prstr
mov dx,offset erms30 ; Complain.
int dos
ret
take2: mov bx,takadr
add bx,size takinfo
push bx
lea dx,[bx].takfcb
mov comand.cmcr,0 ; Filename must be specified.
mov ah,cmifi
mov bx,offset filhlp1
call comnd
pop bx
ret ; Make sure this is three bytes long.
nop
pop bx
mov byte ptr [bx].takfcb+32,0 ; have to clear current record in fcb
mov ah,openf
lea dx,[bx].takfcb
int dos
cmp al,0FFH ; File not found?
jne take3
mov ah,prstr
mov dx,offset erms31
int dos
take3: inc taklev
mov takadr,bx
mov ax,word ptr [bx+16].takfcb
mov [bx].takcnt,ax
mov ax,word ptr [bx+18].takfcb
mov [bx].takcnt+2,ax ; copy size into takinfo
cmp flags.takflg,0
je take4
mov ah,prstr
mov dx,offset crlf
int dos
take4: call takrd ; Get a buffer full of data.
jmp rskp
TAKE ENDP
TAKRD PROC NEAR
push bx
push cx
push dx
mov bx,takadr
cmp byte ptr [bx].takfcb,0feh ; is it a 2.0 file handle?
jne takrd1 ; no, handle differently
push bx ; save frame address
lea dx,[bx].takbuf ; buffer to read into
mov cx,dmasiz ; # of bytes to read
mov ah,readf2 ; 2.0 read call
mov bx,word ptr [bx].takfcb+1 ; file handle is stored here
int dos
pop bx ; restore frame address
jmp takrd2 ; rejoin common exit
takrd1: mov ah,setdma
lea dx,[bx].takbuf
int dos
mov ah,readf
lea dx,[bx].takfcb
int dos
mov ah,setdma
lea dx,buff
int dos
takrd2: mov [bx].takchl,dmasiz
lea ax,[bx].takbuf
mov [bx].takptr,ax
pop dx
pop cx
pop bx
ret
TAKRD ENDP
; copy the path into pthbuf
; enter with ax/ environment segment address
; works in 2.0 only.
getpath proc near
push es
mov bx,ds
mov es,bx ; address data segment
mov bx,offset pthnam ; thing to find
mov cx,pthlen ; length of it
mov dx,offset pthbuf ; place to put it
mov byte ptr pthbuf,0 ; initialize to null...
call getenv ; get environment value
pop es
ret ; and return
getpath endp
; copy the comspec into cmspbuf
; enter with ax/ environment segment address
; works in 2.0 only.
getcsp proc near
push es
mov bx,ds
mov es,bx ; address data segment
mov bx,offset cmspnam ; thing to find
mov cx,cmsplen ; length of it
mov dx,offset cmspbuf ; place to put it
call getenv ; get environment value
pop es
ret ; and return
getcsp endp
; find a path variable. Enter with ax/ environment segment,
; bx/ variable to find (incl =), cx/ length of variable name,
; dx/ address to store value at.
; The buffer given in dx is unchanged if the variable isn't found
getenv proc near
push ds
push es
mov es,ax ; address segment
mov di,0 ; offset in segment
geten1: cmp es:byte ptr [di],0 ; end?
je geten4 ; yes, forget it
push cx ; save counter
push di ; and offset
mov si,bx
repe cmpsb ; is it the one?
pop di
pop cx ; restore these
je geten2 ; found it, break loop
push cx ; preserve again
mov cx,0ffffh ; bogus length
mov al,0 ; marker to look for
repne scasb ; search for it
pop cx ; restore length
jmp geten1 ; loop thru rest of environment
geten2: add di,cx ; skip to definition
mov si,di ; this is source
mov di,dx ; destination as given
mov ax,ds
mov bx,es
mov ds,bx
mov es,ax ; exchange segment regs for copy
geten3: lodsb ; get a byte
stosb ; drop it off
cmp al,0 ; end of string
jne geten3 ; no, go on
geten4: pop es
pop ds ; restore registers
ret ; and return
getenv endp
; put kermit.ini onto take stack if it exists. Just like
; the take command, except it doesn't read a filename.
rdinit proc near ; read kermit init file...
mov al,dosnum ; get dos version
or al,al
jne rdini4 ; post 2.0, use file handle instead...
mov bx,takadr
add bx,size takinfo ; bump take ptr, point to current take frame
lea di,[bx].takfcb ; destination is fcb
mov ax,ds
mov es,ax ; destination segment = source segment
mov si,offset ininam ; name of init file
mov cx,12 ; 8 char name + 3 char ext + 1 char drive...
rep movsb ; copy it in
mov byte ptr [bx].takfcb+32,0 ; have to clear current record in fcb
mov ah,openf
lea dx,[bx].takfcb
int dos
cmp al,0FFH ; File not found?
jne rdini1 ; no, keep going
ret ; else just return, no init file
rdini1: inc taklev ; bump take level
mov takadr,bx ; save current take frame ptr
mov ax,word ptr [bx+16].takfcb
mov [bx].takcnt,ax
mov ax,word ptr [bx+18].takfcb
mov [bx].takcnt+2,ax ; copy size into takinfo
rdini2: cmp flags.takflg,0
je rdini3
mov ah,prstr
mov dx,offset crlf
int dos
rdini3: call takrd ; Get a buffer full of data.
ret
rdini4: mov ax,offset ininm2 ; name to try
push bx
call spath ; can we find it?
pop di
jc rdini6 ; no, forget it, go use it
mov dx,ax ; point to name
mov ah,open2 ; 2.0 open function
mov al,0 ; for reading...
int dos
jc rdini6 ; can't open, forget it
rdini5: inc taklev ; bump take level
add takadr,size takinfo
mov di,takadr ; get current frame ptr
mov word ptr [di].takfcb+1,ax ; save file handle
mov byte ptr [di].takfcb,0feh ; mark as a handle
mov bx,ax ; move file ptr
mov ah,lseek
mov al,2
mov cx,0
mov dx,0 ; seek to end of file
int dos
mov [di].takcnt,ax ; copy file size
mov [di].takcnt+2,dx ; into structure
mov al,0
mov ah,lseek
mov cx,0
mov dx,0
int dos ; seek back to beginning
jmp rdini2 ; go rejoin common exit
rdini6: ret ; no init file, just return
rdinit endp
; get command line into a macro buffer.
gcmdlin proc near
push ds
push es
cld
mov es,psp ; address psp
mov ch,0
mov cl,es:[cline] ; length of cmd line
mov di,cline+1 ; point to actual line
mov al,' '
jcxz gcmdl3 ; no command line, forget it.
repe scasb ; skip over spaces
je gcmdl3 ; all spaces, forget it
mov si,di ; this is first non-space
dec si ; pre-incremented...
inc cx
inc taklev ; bump take level
add takadr,size takinfo ; address new take frame
mov bx,takadr
mov byte ptr [bx].takfcb,0ffh ; mark as a macro
push cx ; save length
push ds ; and segment
lea di,[bx].takbuf ; into take buffer
mov ax,ds
mov ds,psp
mov es,ax ; switch segments for copy
gcmdl1: lodsb ; get a byte
cmp al,',' ; comma?
jne gcmdl2 ; no, keep going
mov al,cr ; convert to cr
gcmdl2: stosb ; deposit it
loop gcmdl1 ; copy whole cmd
pop ds ; restore segment
mov si,offset eexit ; something to tack onto end
mov cx,leexit ; length of it
rep movsb ; copy it in
pop cx ; restore len
add cx,leexit ; count wnat we added
lea ax,[bx].takbuf
mov [bx].takptr,ax ; init buffer ptr
mov [bx].takchl,cl ; chars remaining
mov [bx].takcnt,cx ; and all chars
mov [bx].takcnt+2,0 ; clear high order
gcmdl3: pop es
pop ds
ret
gcmdlin endp
; This routine prints the prompt and specifies the reparse address.
PROMPT PROC NEAR
mov comand.cmprmp,dx ; save the prompt
pop bx ; Get the return address.
mov comand.cmrprs,bx ; Save as addr to go to on reparse.
mov comand.cmostp,sp ; Save for later restoral.
push bx ; Put it on the stack again.
mov bx,offset comand.cmdbuf
mov comand.cmcptr,bx ; Initialize the command pointer.
mov comand.cmdptr,bx
mov ah,0
mov comand.cmaflg,ah ; Zero the flags.
mov comand.cmccnt,ah
mov comand.cmsflg,0FFH
cmp flags.takflg,0 ; look at take flag
jne promp1 ; supposed to echo, skip this check...
cmp taklev,0 ; inside a take file?
je promp1 ; no, keep going
ret ; yes, return
promp1: mov ah,prstr
mov dx,offset crlf
int dos
mov ah,prstr ; Print the prompt.
mov dx,comand.cmprmp
int dos
ret
PROMPT ENDP
; Erase specified file(s).
DELETE PROC NEAR
mov comand.cmcr,0 ; Filename must be specified.
mov ah,cmifi ; Parse an input filespec.
mov dx,offset fcb
mov bx,offset filhlp2 ; Text of help message.
call comnd
jmp r ; Bad filename.
mov ah,cmcfm ; Parse a confirm.
call comnd
jmp r
cld
mov di,offset fcb+1
mov al,'?'
mov cx,11 ; # of chars in a name
repe scasb ; are they all ?'s?
jne del1 ; no, skip message
mov dx,offset infms1
call prompt
mov ah,cmkey
mov dx,offset yestab
mov bx,0
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd
pop bx
ret
nop
pop bx
cmp bx,0
jne del1
jmp rskp
del1: mov dx,offset fcb
mov ah,sfirst ; See if any files match this specification.
int dos
cmp al,0FFH ; No matches?
jne del2
mov ah,prstr
mov dx,offset erms32
int dos
jmp rskp
del2: mov dx,offset fcb
mov ah,delf ; Erase the file(s).
int dos
mov dx,offset infms8
mov ah,prstr ; Say we did so.
int dos
jmp rskp
DELETE ENDP
CHKDSK PROC NEAR
mov ah,cmcfm
call comnd
jmp r
cmp dosnum,0
je chkds1 ; yes, have to do it the hard way
mov si,offset chkdcmd ; point to cmd
mov cx,chkdlen ; and length
jmp crun ; and go execute it nicely
chkds1: push es
mov ax,ds
mov es,ax
mov di,offset fcb
mov si,offset chkfil
mov cx,chkflen
rep movsb
mov dx,offset stk + 15 ; End of stack plus roundoff.
mov cl,4
shr dx,cl ; Divide to get segment.
add dx,seg stack ; Get past the stack.
mov es,dx ; remember where segment is.
mov ah,makseg ; Create new PSP.
int dos
mov ax,siz ; Update machine size.
mov es:2,ax
mov es: byte ptr [deffcb],0 ; Blank default fcb.
mov di,deffcb+1
mov al,' ' ; Blank out fcb.
mov cx,fcbsiz
rep stosb
mov word ptr es:[terma],offset term ; Termination address.
mov es:[terma+2],cs
mov ah,openf
mov dx,offset fcb
int dos
inc al
jnz chkok
mov dx,offset erms33
mov ah,prstr
int dos
jmp chkend
chkok: mov byte ptr fcb+32,0 ; set current record field
mov di,100h ; offset to copy into
lp: mov dx,offset fcb
mov ah,readf
int dos
push ax ; save status
mov si,offset buff
mov cx,dmasiz/2 ; Word size of DMA
rep movsw ; copy into new segment...
pop ax
cmp al,1 ; End of file
je dun
cmp al,3 ; Done here too
jne lp
dun: mov ssave,sp ; Save stack pointer.
mov ax,es
mov word ptr cs:[doit+2],ax ; Set segment for CHKDSK.
mov ds,ax
mov ss,ax
mov ax,0
jmp cs: dword ptr [doit] ; Call CHKDSK.
term: mov ax,seg datas ; Reset data area.
mov ds,ax
mov sp,ssave
mov ax,seg stack
mov ss,ax
mov ah,setdma
mov dx,offset buff
int dos ; restore dma address!!
chkend: pop es
jmp rskp
doit dd 100h
CHKDSK ENDP
; Get directory listing.
DIRECT PROC NEAR
mov ah,dosver ; See what level of DOS we're at.
int dos
cmp al,0 ; Level 2.0 or above?
jne dir4 ; Yes - get directory the easy way.
mov comand.cmcr,1 ; Allow plain CR (so DIR == DIR *.*).
mov ah,cmifi ; Get input file spec.
mov dx,offset fcb ; Give the address for the FCB.
mov bx,offset filhlp3
call comnd
jmp r
mov ah,cmcfm ; Parse a confirm.
call comnd
jmp r
mov comand.cmcr,0 ; Reset this.
push es
mov ax,ds
mov es,ax
mov temp1,0FFH
mov di,offset nambuf
dir0: call getfn ; Get a matching file name.
cmp al,0FFH ; Retcode -- are we done?
je dir1 ; Yes, just leave.
call dumpit ; Print it or dump to buffer.
jmp dir0
dir1: pop es
jmp rskp
dir4: mov si,offset cmspbuf ; command processor
mov di,offset dirnam
dir5: lodsb ; get a byte
or al,al
jz dir6 ; stop on the null
stosb ; otherwise copy it in
jmp dir5 ; and keep going
dir6: mov si,offset dircmd ; add directory command to it
mov cx,dirclen
rep movsb
mov ah,cmtxt ; parse with cmtxt so we can have paths...
mov bx,di ; next available byte
mov dx,offset filwmsg ; In case user wants help.
call comnd
jmp r
mov cl,ah
mov ch,0 ; length of name
sub di,offset dirnam ; compute # of bytes used
add cx,di
mov si,offset dirnam ; dir cmd
jmp crun ; join run cmd from there.
DIRECT ENDP
getfn: cmp temp1,0FFH
jne gtfn1
mov ah,sfirst ; Any matches?
mov dx,offset fcb
int dos
cmp al,0FFH ; Means no matches.
je gtfn5
call savfcb
mov temp1,0
jmp gtfn4
gtfn1: cmp flags.wldflg,0FFH ; Wilcard seen?
je gtfn2 ; Yes, get next file.
mov al,0FFH ; No, set retcode.
ret
gtfn2: call rstfcb
mov ah,snext
mov dx,offset fcb
int dos
cmp al,0 ; Any more matches?
je gtfn3 ; Yes keep going.
mov al,0FFH ; OK return code.
ret
gtfn3: call savfcb
gtfn4: push di
mov si,offset buff ; Data is here.
mov di,offset fcb ; Copy to here.
mov cx,37
repne movsb
pop di
call nicnam ; Make name nice for printing.
mov al,0
ret
gtfn5: mov ah,prstr ; Don't print if a server.
mov dx,offset erms32 ; Say no matches.
int dos
mov al,0FFH ; Failure return code.
ret
savfcb: push di
mov si,offset fcb ; Data is here.
mov di,offset cpfcb ; Copy to here.
mov cx,37
repne movsb
pop di
ret
rstfcb: push di
mov si,offset cpfcb ; Data is here.
mov di,offset fcb ; Copy to here.
mov cx,37
repne movsb
pop di
ret
nicnam: mov al,CR ; Add CRLF before print names
stosb
mov al,LF
stosb
mov cx,8
mov si,offset fcb+1
repne movsb ; Get the file name.
mov al,' '
stosb
mov cx,3
repne movsb
mov al,tab
stosb
mov al,' '
stosb
mov ah,openf
mov dx,offset fcb
int dos
mov bx,offset fcb+18 ; Get hi order word of file size.
mov ax,[bx]
mov dx,ax
mov bx,offset fcb+16 ; Get lo order word.
mov ax,[bx]
call nout2x ; Get it in decimal.
mov al,tab
stosb
mov al,' '
stosb
mov ah,0
mov si,offset fcb+20
lodsb
mov fildat+1,al
lodsb
mov fildat,al ; Date field of fcb.
mov cl,5
shr fildat+1,cl
and fildat,1
mov cl,3
shl fildat,cl
mov al,fildat
or al,fildat+1 ; Get the month field.
cmp al,9
jg nic0
push ax
mov al,' '
stosb
pop ax
nic0: call nout2 ; Make it decimal.
mov al,'-'
stosb
mov si,offset fcb+20 ; Get date field.
lodsb
and al,1FH
cmp al,10 ; Only one digit?
jge nic0x
push ax
mov al,'0' ; Make it two digits.
stosb
pop ax
nic0x: call nout2 ; Make it decimal.
mov al,'-'
stosb
mov si,offset fcb+21 ; Get the year field.
lodsb
shr al,1
add al,80
cmp al,100 ; At the year 2000 or above?
js nic0y ; No, just go on.
sub al,100 ; Go back to two digits.
nic0y: cmp al,10 ; Only one digit?
jge nic0z
push ax
mov al,'0' ; Make it two digits.
stosb
pop ax
nic0z: call nout2 ; Make it decimal.
mov al,tab
stosb
mov si,offset fcb+23 ; Get time field of fcb.
lodsb
mov cl,3 ; Get the hour field.
shr al,cl
mov tmp,'a' ; For AM.
cmp al,12 ; Before noon?
jl nic1
mov tmp,'p' ; It's PM.
je nic1 ; Don't change "12" to "0".
sub al,12 ; Use a 12 hr. clock.
nic1: cmp al,0 ; Just after midnight?
jne nic1x
add al,12 ; Make it "12" instead of "0".
nic1x: cmp al,10 ; Pad with a space?
jge nic2
push ax
mov al,' '
stosb
pop ax
nic2: call nout2 ; Make it decimal.
mov al,':' ; Separate hours and minutes.
stosb
mov si,offset fcb+23 ; Get the minutes field.
lodsb
and al,07
mov cl,3
shl al,cl
mov ah,al
mov si,offset fcb+22
lodsb
mov cl,5
shr al,cl
or al,ah
mov ah,0
cmp al,10 ; Would there be a leading zero.
jge nic3
push ax
mov al,'0'
stosb
pop ax
nic3: call nout2 ; Make it decimal.
mov al,tmp ; Add 'a' (AM) or 'p' (PM).
stosb
mov ah,closf
mov dx,offset fcb
int dos
ret
; For now, just print it.
dumpit: mov al,'$'
stosb
mov ah,prstr
mov dx,offset nambuf
int dos
mov di,offset nambuf
ret
; push to an inferior command parser
; entry fpush (fast push...) pushes without waiting for a confirm.
; returns rskp.
dopush proc near
cmp dosnum,0 ; < 2.0 ?
jne dopus1 ; no, go on
mov dx,offset erms34
mov ah,prstr
int dos
jmp rskp
dopus1: mov ah,cmcfm
call comnd
jmp r
fpush: mov si,offset cmspbuf ; name of parser
push si ; save beginning
sub cx,cx ; initial length
dopus2: lodsb
inc cx ; count this
or al,al ; at end?
jnz dopus2 ; no, keep going
pop si ; restore cmd
dec cx ; this is incremented one over
jmp short crun ; go run it
dopush endp
; crun - run an arbitrary program. Enter with si/address of whole
; cmd, cx/length of cmd.
CRUN proc near
push cx ; save length of cmd
mov ax,ds
mov es,ax ; address dest segment
mov di,offset nambuf
rep movsb ; copy command so we can mess with it
pop cx
mov si,offset nambuf ; point to command
jmp short run3 ; and join run code
CRUN ENDP
RUN PROC NEAR
cmp dosnum,0
jne run1
mov ah,prstr
mov dx,offset erms34 ; Complain.
int dos
jmp rskp
run1: mov ah,cmtxt ; Get program name.
mov bx,offset nambuf ; Convenient buffer.
mov dx,offset filmsg ; In case user wants help.
call comnd
nop
nop
nop
cmp ah,0
jne run2
mov ah,prstr
mov dx,offset erms35
int dos
jmp rskp
run2: mov cl,ah
mov ch,0
mov si,offset nambuf
; alternate entry if cmd is already known. Source cmd ptr in si
; is trashed.
run3: mov bx,cx
mov byte ptr [si+bx],cr ; end string with a cr for dos.
mov di,offset cmdnam
mov ax,ds
mov es,ax
run4: lodsb
cmp al,' '
jne run5
dec si ; back up over space
jmp short run6 ; and exit loop
run5: stosb
loop run4
run6: mov byte ptr [di],0 ; terminate string
dec si ; point back a byte into argument
mov [si],cl ; put length of argument here
mov exearg+2,si ; pointer to argument string
mov exearg+4,ds ; segment of same
inc si ; pass length over
mov al,1 ; scan leading separators
mov di,offset exefcb ; parse into this fcb
mov ah,prsfcb
int dos ; go parse the fcb
mov al,1 ; scan leading separators
mov di,offset exefcb2 ; second fcb to fill
mov ah,prsfcb
int dos ; parse the fcb
mov es,psp ; point to psp again
mov ax,es:[env] ; get environment ptr
mov exearg,ax ; put into argument block
mov bx,offset stk + 15 ; end of pgm
mov cl,4
shr bx,cl ; compute # of paragraphs in last segment
mov ax,seg stack ; end of kermit
sub ax,psp ; minus beginning...
add bx,ax ; # of paragraphs occupied
mov ah,setblk
int dos
jc run7 ; nope...
mov ax,ds
mov es,ax ; put es segment back
mov ax,offset cmdnam ; point to cmd name again
call spath ; look for it
jc run8 ; not found, go complain
mov dx,ax ; point to command name
mov al,0 ; load and execute...
mov ah,exec
mov bx,offset exearg ; and to arguments
mov ssave,sp ; save stack ptr
int dos ; go run the program
mov ax,seg datas
mov ds,ax ; reset data segment
mov ax,seg stack
mov ss,ax ; and stack segment
mov sp,ssave ; restore stack ptr
mov ah,setdma
mov dx,offset buff
pushf ; save flags
int dos ; restore dma address!!
popf ; recover flags
jc run8 ; error, handle.
jmp rskp ; ok, return
run7: mov ah,prstr
mov dx,offset erms36
int dos
jmp rskp
run8: mov ah,prstr
mov dx,offset erms37
int dos
jmp rskp
RUN ENDP
; the show command
showcmd proc near
mov ah,cmkey
mov dx,offset shotab
xor bx,bx ; no canned help
call comnd
jmp r
call bx ; call the handler
jmp r
jmp rskp ; and return
showcmd endp
intbrk: cmp flags.debug,1 ; Debug mode?
je intb1 ; Yes, then don't ignore the ^C.
push ax
push ds
mov ax,seg datas
mov ds,ax
mov flags.cxzflg,'C' ; Say we saw a ^C.
mov pack.state,'A' ; Set the state to abort.
pop ds
pop ax
iret
intb1: jmp in3ad ; Original break interrupt address.
NOUT2 PROC NEAR
push ax
push dx
mov temp,10 ; Divide quotient by 10.
cwd ; Convert word to doubleword.
div temp ; AX <-- Quo, DX <-- Rem.
cmp ax,0 ; Are we done?
jz nout0 ; Yes.
call nout2 ; If not, then recurse.
nout0: add dl,'0' ; Make it printable.
mov temp,ax
mov al,dl
stosb
mov ax,temp
pop dx
pop ax
ret ; We're done. [21c]
NOUT2 ENDP
NOUT2X PROC NEAR
push ax
push dx
push cx
mov temp,10 ; Divide quotient by 10.
div temp ; AX <-- Quo, DX <-- Rem.
mov cx,dx ; Remember the remainder.
cmp ax,0 ; Are we done?
jz nout0x ; Yes.
mov dx,0
call nout2 ; If not, then recurse.
nout0x: add cl,'0' ; Make it printable.
mov temp,ax
mov al,cl
stosb
mov ax,temp
pop cx
pop dx
pop ax
ret ; We're done. [21c]
NOUT2X ENDP
SPATH proc near
; enter with ax/ ptr to file name. Searches path for given file,
; returns with ax/ ptr to whole name, or carry on if file isn't
; to be found.
push es
mov bx,ds
mov es,bx ; address data segment
mov bx,ax ; convenient place to keep this
call isfile ; does it exist as it is?
mov ax,bx ; ifso, just return original name
jc spath0 ; nope...
pop es
ret
spath0: mov si,ax
mov di,offset tfile ; place to copy to
mov dl,0 ; no '\' seen yet
spath1: lodsb
stosb
cmp al,'/' ; contain path characters?
je spath1a
cmp al,'\'
jne spath2 ; no, keep going
spath1a:mov dl,1 ; remember we've seen them
spath2: or al,al
jnz spath1 ; copy name in
or dl,dl ; look at flag
jnz spath3 ; path embedded, file not there, fail
; no path, keep going
spath3: mov si,offset pthbuf ; path definition
cmp byte ptr [si],0 ; empty path?
jne spath4 ; no, keep going
mov ah,gcd ; get current dir
mov dl,0 ; for default drive
mov si,offset defpth+1 ; place to put it
int dos
mov si,offset defpth ; point to the path
spath4: cmp byte ptr [si],0 ; null, exit loop
je spath9
mov di,offset tfile ; place to put name
spath5: lodsb ; get a byte
cmp al,';' ; end of this part?
je spath7 ; yes, break loop
cmp al,0 ; maybe end of string?
jne spath6 ; no, keep going
dec si ; back up over it
jmp short spath7 ; and break loop
spath6: stosb ; else stick in dest string
jmp spath5 ; and continue
spath7: push si ; save this ptr
mov si,bx ; this is user's file name
cmp byte ptr [di-1],'/' ; does it end with switch char?
je spath8 ; yes, don't put one in
mov al,'\' ; how about this one?
cmp byte ptr [di-1],al
je spath8 ; yes, don't put it in.
stosb ; else add one
spath8: lodsb
stosb
or al,al
jnz spath8 ; copy rest of name
pop si ; restore pos in path def
mov ax,offset tfile
call isfile ; is it a file?
jc spath4 ; no, keep looking
mov ax,offset tfile
pop es
ret ; return success (carry off)
spath9: pop es ; restore this
stc ; no file found
ret
spath endp
isfile proc near
; returns carry off if the file pointed to by ax exists
mov dx,ax ; copy ptr
mov al,0 ; don't change anything
mov ah,chmod
int dos
ret ; dos sets carry
isfile endp
; Jumping to this location is like retskp. It assumes the instruction
; after the call is a jmp addr.
RSKP PROC NEAR
pop bp
add bp,3
push bp
ret
RSKP ENDP
; Jumping here is the same as a ret.
R PROC NEAR
ret
R ENDP
code ends ; End of code section.
end start